import {GraphStyle} from "@/utils/styles";

interface OptionType {
    beforeAdd: (model: object, type: string) => Promise<any> | undefined,
    afterAdd: (model: object, type: string) => Promise<any> | undefined,
}

export function dragEdge(G6, option: OptionType) {
    G6.registerBehavior('drag-edge', {
        getDefaultCfg() {
            return {
                updateEdge: true,
                delegate: true,
                delegateStyle: {},
                dragEdge: false,
            };
        },
        getEvents() {
            return {
                'anchor:dragstart': 'onDragStart',
                'anchor:drag': 'onDrag',
                'anchor:dragenter': 'onDragEnter',
                'anchor:dragleave': 'onDragLeave',
                'anchor:dragend': 'onDragEnd',
            };
        },
        onDragStart(e) {
            const node = e.target.getParent().getParent().get('item');
            const anchor = e.item
            const anchorIndex = anchor.index
            const point = node.getAnchorPoints()[anchorIndex];

            this.target = e.item;
            this.origin = {
                x: point.x,
                y: point.y,
                sourceNode: node,
                sourceAnchor: anchorIndex
            };

            this.graph.getNodes().forEach(node => {
                node.showAnchor(this.graph)
                node.getContainer().anchorShapes.forEach(a => {
                    a.get('item').showHotpot()
                })
            });

            this.graph.set('onDragEdge', true);
        },
        onDrag(e) {
            if (!this.origin) {
                return;
            }
            this._updateEdge(this.target, e);
        },
        onDragEnter(e) {
            if (!this.origin) {
                return;
            }
            if (!this.sameNode(e)) {
                e.item.setHotspotActived(true);
                this.origin.targetNode = e.target.getParent().getParent().get('item');
                this.origin.targetAnchor = e.item.get('index');
            }
        },
        onDragLeave(e) {
            if (!this.origin) {
                return;
            }
            if (!this.sameNode(e)) {
                e.item.setHotspotActived(false);
                this.origin.targetNode = null;
                this.origin.targetAnchor = null;
            }
        },
        onDragEnd(e) {
            if (!this.origin) {
                return;
            }
            const delegateShape = e.item.get('edgeDelegate');
            if (delegateShape) {
                delegateShape.remove();
                this.target.set('edgeDelegate', null);
            }
            this._updateEdge(this.target, e, true);
            this.target = null;
            this.origin = null;
            this.graph.set('onDragEdge', false);

            this.graph.getNodes().forEach(node => {
                node.hideAnchor(this.graph)
                node.getContainer().anchorShapes.forEach(a => {
                    a.get('item').hideHotpot()
                })
            });
        },
        sameNode(e) {
            return e.target.type === 'marker' && e.target.getParent() && e.target.getParent().getParent().get('item').get('id') === this.origin.sourceNode.get('id')
        },
        _updateEdge(item, e, force) {
            const x = e.x;
            const y = e.y;
            if (this.delegate && !force) {
                this._updateEdgeDelegate(item, x, y);
                return;
            }
            this._addEdge(e);
            this.graph.paint();
        },
        _updateEdgeDelegate(item, x, y) {
            const self = this;
            let edgeShape = item.get('edgeDelegate');
            if (!edgeShape) {
                const parent = self.graph.get('group');
                edgeShape = parent.addShape('line', {
                    attrs: {
                        x1: this.origin.x,
                        y1: this.origin.y,
                        x2: x,
                        y2: y,
                        ...GraphStyle.edgeDelegationStyle,
                    }
                });
                edgeShape.set('capture', false);
                item.set('edgeDelegate', edgeShape);
            }
            edgeShape.attr({x2: x, y2: y});
            this.graph.paint();
        },
        async _addEdge() {
            if (this.origin.targetNode) {
                const addModel = {
                    clazz: 'flow',
                    source: this.origin.sourceNode.get('id'),
                    target: this.origin.targetNode.get('id'),
                    sourceAnchor: this.origin.sourceAnchor,
                    targetAnchor: this.origin.targetAnchor,
                }
                if (this.graph.executeCommand) {
                    this.graph.executeCommand('add', {
                        type: 'edge',
                        addModel: addModel
                    });
                } else {
                    try {
                        if (!!option.beforeAdd) {
                            await option.beforeAdd(addModel, 'edge')
                        }
                        this.graph.emit('add-edge:before')
                        this.graph.add('edge', addModel);
                        this.graph.emit('add-edge:after')
                        if (!!option.afterAdd) {
                            await option.afterAdd(addModel, 'edge')
                        }
                    } catch (e) {
                        console.error(e)
                    }
                }
            }
        }
    });
}